<script>
import FormParam from '@/components/form/FormParam.vue'
import FormItem from '@/components/form/FormItem.vue'
/**获取字符串宽度
 * @param {string} str 字符串
 * @param {string} [size] 字体大小，例如：12px、1rem
 * @param {string} [family] 字体
 * @returns {number} 宽度，单位px
 */
function string_width(str, size, family){
  const tempEl = document.createElement('span');
  if (size) tempEl.style.fontSize = size;
  if (family) tempEl.style.fontFamily = family;
  tempEl.style.position = 'absolute';
  tempEl.style.visibility = 'hidden';
  tempEl.innerText = str;

  // 将元素添加到文档中
  document.body.appendChild(tempEl);

  // 获取宽度
  const width = tempEl.offsetWidth;

  // 移除临时元素
  document.body.removeChild(tempEl);

  return width;
}

export default {
  _tip_: '',
  components: { FormItem, FormParam},
  props: {
    param_list: [Array, Object], // 表单参数列表
    empty_name: Boolean, //是否使用空name，部分内嵌的表单，但内嵌表单数据不提交的情况使用
    button_list: {
      type: [Array, Object],
    }, // 按钮列表，包含参数：title、onClick、type、size 等。
  },
  emits: ['change', 'submit'],
  data() {
    return {
      init_value_json: '{}',
    }
  },
  methods: {
    form_data(){
      return Object.values(this.param_list).reduce((res,row)=>{
        if (row.name) res[row.name] = row.value;
        return res;
      },{});
    },
    validate_row(row){
      // TODO 更复杂的验证后面如果需要，再行优化
      row.error = '';
      let validate = row.validate || [];
      if (~validate.indexOf('required') && !row.value){
        row.error = '必填';
      }
    },
    change_row(row, v) {
      row.value = v;
      this.validate_row(row);

      let data = this.form_data();
      console.log(data);
      this.$emit('change', this.form_data());
      // if (typeof(row.onchange) == 'function') row.onchange(row, v);
    },
    submit(){
      let pass = true;
      Object.values(this.param_list).forEach(row => {
        this.validate_row(row);
        pass = pass && !row.error;
      })
      if (!pass) return console.error('表单验证不通过');
      let data = new FormData(this.$el);
      this.$emit('submit',data);
    },
    init(init_value){
      this.errors = {};
      let value_arr = JSON.parse(this.init_value_json);
      if (typeof(init_value)=='object') {
        Object.assign(value_arr, init_value);
        this.init_value_json = JSON.stringify(value_arr);
      }
      Object.values(this.param_list).forEach(row => {
        if (!row.name || typeof(value_arr[row.name]) === 'undefined') return;
        row.value = value_arr[row.name];
      })
    },
    set_init_value(){
      let init_value = {};
      Object.values(this.param_list).forEach(row => {
        if (!row.name) return;
        init_value[row.name] = typeof(row.value==='undefined') ? '' : row.value;
      })
      this.init_value_json = JSON.stringify(init_value);
    },

  },
  computed: {
    label_width(){
      let max = 0;
      Object.values(this.param_list).forEach(row => {
        if (!row.label) return;
        max = Math.max(string_width(row.label, '14px'), max);
      })
      return (max+26)+'px';
    },
    this_button_list(){
      if (this.button_list) return this.button_list;
      return [
        {title:'重置', type:'', onClick:()=>{ this.init(); }},
        {title:'提交', type:'primary', onClick:()=>{ this.submit(); }},
      ]
    }
  }
}
</script>

<template>
  <el-form class="forms" action="" @submit.prevent="submit" :label-width="label_width">
    <template v-for="(row,i) in param_list" :key="i">

      <form-item v-bind="row" :name="empty_name?'':row.name" :modelValue="row.value" @update:modelValue="change_row(row, $event)">
        <template v-for="(name) in Object.keys($slots)" v-slot:[name]="slotProps">
          <slot :name="name" v-bind="slotProps"></slot>
        </template>
      </form-item>

      <div v-if="row.br" style="height: 0;width: 100%;" tip="强行换行"></div>
    </template>

    <input type="submit" text="提交">
    <div class="button-list">
      <el-button v-for="(row,i) in this_button_list" :key="i" v-bind="row">{{ row.title }}</el-button>
    </div>
  </el-form>
</template>

<style scoped lang="scss">
.forms{display: flex;flex-wrap: wrap;}
.button-list{text-align: center;width: 100%;}
.button-list .el-button{margin: 0 3px;}
</style>